import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.Mockito.*;

public class ConnectionTest {
	Telephone phoneMock;
	MailSystem mailSystemMock;
	Connection connection;
	Mailbox box = new Mailbox("123", "Hello everybody");
	String greeting = "Hola a todos";
	
	@Before
	public void doBefore()
	{
		phoneMock = mock(Telephone.class);
		mailSystemMock = mock(MailSystem.class);
	}

	@Test
	public void testConnection()
	{
		connection = new Connection(mailSystemMock, phoneMock);
		
		assertTrue(connection.isConnected());
		verify(phoneMock).showDisplay("Enter mailbox number followed by #");
	}
	
	@Test
	public void testConnectAndChangeToRecordingStatus()
	{
		connection = new Connection(mailSystemMock, phoneMock);		
		
		findMailBox();
		
		assertTrue(connection.isRecording());
		verify(phoneMock).showDisplay(box.getGreeting());
	}
	
	@Test
	public void testConnectAndDontFindMailBox()
	{
		connection = new Connection(mailSystemMock, phoneMock);
		
		when(mailSystemMock.findMailbox("12")).thenReturn(null);
		connection.dial("1");
		connection.dial("2");
		connection.dial("#");
		
		assertFalse(connection.isRecording());
		verify(phoneMock).showDisplay("Incorrect mailbox number. Try again!");
	}
	
	@Test
	public void testLoginSucessfull()
	{
		connection = new Connection(mailSystemMock, phoneMock);		
		
		login();
		assertTrue(connection.isMailBoxMenuStatus());
		verify(phoneMock).showDisplay("Enter 1 to listen to your messages\n"
		         + "Enter 2 to change your passcode\n"
		         + "Enter 3 to change your greeting");
	}
	
	@Test
	public void testLoginPasswordIncorrect()
	{
		connection = new Connection(mailSystemMock, phoneMock);		
		
		findMailBox();
		
		// Login!
		connection.dial("1");
		connection.dial("1");
		connection.dial("2");
		connection.dial("#");
		assertFalse(connection.isMailBoxMenuStatus());
		verify(phoneMock).showDisplay("Incorrect passcode. Try again!");
	}
	
	@Test
	public void testGoToMessageMenuStatus()
	{
		connection = new Connection(mailSystemMock, phoneMock);		
		
		login();	
		
		// Pass to mailBoxMenu
		connection.dial("1");
		assertTrue(connection.isMessageMenuStatus());
		verify(phoneMock).showDisplay("Enter 1 to listen to the current message\n"
         + "Enter 2 to save the current message\n"
         + "Enter 3 to delete the current message\n"
         + "Enter 4 to return to the main menu");
	}
	
	@Test
	public void testGoToChangePassCodeStatus()
	{
		connection = new Connection(mailSystemMock, phoneMock);		
		
		login();	
		
		// Pass to Change pass code status
		connection.dial("2");
		assertTrue(connection.isChangePassCodeStatus());
		verify(phoneMock).showDisplay("Enter new passcode followed by the # key");
	}
	
	@Test
	public void testGoToChangeGreetingStatus()
	{
		connection = new Connection(mailSystemMock, phoneMock);		
		
		login();	
		
		// Pass to Change Greeting status
		connection.dial("3");
		assertTrue(connection.isChangeGreetingStatus());
		verify(phoneMock).showDisplay("Record your greeting, then press the # key");
	}
	
	@Test
	public void changePassCodeTest()
	{
		connection = new Connection(mailSystemMock, phoneMock);		
		
		login();	
		
		// Pass to Change pass code status
		connection.dial("2");
		
		// Change password
		connection.dial("4");
		connection.dial("5");
		connection.dial("6");
		connection.dial("#");
		
		assertTrue(box.checkPasscode("456"));
		assertTrue(connection.isMailBoxMenuStatus());
		verify(phoneMock, atLeast(2) ).showDisplay("Enter 1 to listen to your messages\n"
		         + "Enter 2 to change your passcode\n"
		         + "Enter 3 to change your greeting");
	}
	
	@Test
	public void changeGreetingTest()
	{
		connection = new Connection(mailSystemMock, phoneMock);		
		
		login();		
		
		// Pass to Change Greeting status
		connection.dial("3");
		
		// Change Greeting
		connection.record(greeting);
		connection.dial("#");
		assertEquals(greeting, box.getGreeting());
		assertTrue(connection.isMailBoxMenuStatus());
		verify(phoneMock, atLeast(2)).showDisplay("Enter 1 to listen to your messages\n"
		         + "Enter 2 to change your passcode\n"
		         + "Enter 3 to change your greeting");
	}
	
	@Test
	public void testListenMessageWithASavedMessage()
	{
		connection = new Connection(mailSystemMock, phoneMock);
		box = new Mailbox("123", "Hello everybody");
		String message = "Hola, soy pepito";
		box.addMessage(new Message(message));
		
		passToMailBoxMenu();
		
		// Get message
		connection.dial("1");
		
		verify(phoneMock).speak(message + "\n");
		verify(phoneMock, atLeast(2)).showDisplay("Enter 1 to listen to the current message\n"
		         + "Enter 2 to save the current message\n"
		         + "Enter 3 to delete the current message\n"
		         + "Enter 4 to return to the main menu");
	}
	
	@Test
	public void testListenMessageWithZeroMessages()
	{
		connection = new Connection(mailSystemMock, phoneMock);		
		
		passToMailBoxMenu();
		
		// Get message
		connection.dial("1");
		
		verify(phoneMock).speak("No messages.\n");
		verify(phoneMock, atLeast(2)).showDisplay("Enter 1 to listen to the current message\n"
		         + "Enter 2 to save the current message\n"
		         + "Enter 3 to delete the current message\n"
		         + "Enter 4 to return to the main menu");
	}
	
	@Test
	public void testSaveMessage()
	{
		connection = new Connection(mailSystemMock, phoneMock);
		box = new Mailbox("123", "Hello everybody");
		String message = "Hola, soy pepito";
		
		box.addMessage(new Message(message));
		box.addMessage(new Message("Hola"));
		
		passToMailBoxMenu();
		
		// Save message
		connection.dial("2");
		
		box.removeCurrentMessage();
		assertEquals(message, box.getCurrentMessage().getText());
		verify(phoneMock, atLeast(2)).showDisplay("Enter 1 to listen to the current message\n"
		         + "Enter 2 to save the current message\n"
		         + "Enter 3 to delete the current message\n"
		         + "Enter 4 to return to the main menu");
	}
	
	@Test
	public void testRemoveCurrentMessage()
	{
		connection = new Connection(mailSystemMock, phoneMock);
		box = new Mailbox("123", "Hello everybody");
		String message = "Hola, soy pepito";
		
		box.addMessage(new Message("Hola"));
		box.addMessage(new Message(message));
		
		passToMailBoxMenu();
		
		// Remove message
		connection.dial("3");
		
		assertEquals(message, box.getCurrentMessage().getText());
		verify(phoneMock, atLeast(2)).showDisplay("Enter 1 to listen to the current message\n"
		         + "Enter 2 to save the current message\n"
		         + "Enter 3 to delete the current message\n"
		         + "Enter 4 to return to the main menu");
	}
	
	@Test
	public void returnToMailBoxMenuFromMessageMenu()
	{
		connection = new Connection(mailSystemMock, phoneMock);
		box = new Mailbox("123", "Hello everybody");
		String message = "Hola, soy pepito";
		
		box.addMessage(new Message("Hola"));
		box.addMessage(new Message(message));
		
		passToMailBoxMenu();
		
		// Return to MailBoxMenu
		connection.dial("4");
		assertTrue(connection.isMailBoxMenuStatus());
		verify(phoneMock, atLeast(2)).showDisplay("Enter 1 to listen to your messages\n"
		         + "Enter 2 to change your passcode\n"
		         + "Enter 3 to change your greeting");
	}
	
	public void findMailBox()
	{
		// First find the mailbox
		when(mailSystemMock.findMailbox("12")).thenReturn(box);
		connection.dial("1");
		connection.dial("2");
		connection.dial("#");
	}
	
	public void login()
	{
		findMailBox();
		
		connection.dial("1");
		connection.dial("2");
		connection.dial("3");
		connection.dial("#");
	}
	
	public void passToMailBoxMenu()
	{
		login();
		// Pass to mailBoxMenu
		connection.dial("1");
	}
}
